package com.qiwenshare.file.dingding.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetUserTokenResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import com.qiwenshare.file.dingding.config.AgentConfig;
import com.qiwenshare.file.dingding.constant.DingdingUrlConstants;
import com.qiwenshare.file.redis.RedisCache;
import com.qiwenshare.file.util.StringUtils;
import com.taobao.api.ApiException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 钉钉旧版SDK接口
 */
@Slf4j
@Component
public class DingdingOldSdkApi {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AgentConfig agentConfig;

    private final String DD_ACCESS_TOKEN_KEY_PRE = "DD_ACCESS_TOKEN:";

    private static Interner<String> lock = Interners.newWeakInterner();

    // 获取token，并存入或更新redis
    public String getAccessToken() {
        // 先查询redis是否存在(更新或者初始化时设置过期时间，过期时间比实际token可用时间短，防止实际执行时过期)
        String tokenKey = DD_ACCESS_TOKEN_KEY_PRE + agentConfig.getAgentId();
        String accessToken = redisCache.getCacheObject(tokenKey);
        if (StringUtils.isEmpty(accessToken)) {
            log.info("【钉钉API】请求钉钉接口获取AccessToken");
            synchronized (lock.intern(agentConfig.getAgentName().toString())) {
                log.info("dingding token线程start:" + Thread.currentThread().getName());
                accessToken = redisCache.getCacheObject(tokenKey);
                if (StringUtils.isEmpty(accessToken)) {
                    log.info("dingding token into get...");
                    DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.ACCESS_TOKEN_URL);
                    OapiGettokenRequest request = new OapiGettokenRequest();
                    request.setAppkey(agentConfig.getAppKey());
                    request.setAppsecret(agentConfig.getAppSecret());
                    request.setHttpMethod("GET");
                    try {
                        OapiGettokenResponse response = client.execute(request);
                        accessToken = response.getAccessToken();
                        // 过期时间减少100s
                        Long expiresIn = response.getExpiresIn()-100;
                        redisCache.setCacheObject(tokenKey, accessToken, expiresIn.intValue(), TimeUnit.SECONDS);
                    } catch (ApiException e) {
                        return accessToken;
                    }
                }
                log.info("dingding token线程end:" + Thread.currentThread().getName());
            }
        }
        return accessToken;

    }

    /**
     * 根据父id查询子部门列表
     * @return 查询失败返回空
     */
    public List<DeptSimpleInfo> getDepartmentListsub(Long parentDeptId) {
        String accessToken = getAccessToken();
        List<DeptSimpleInfo> resultArr = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_V2_DEPARTMENT_URL + DingdingUrlConstants.DEPARTMENT_LISTSUB_URL);
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(parentDeptId);
            req.setLanguage("zh_CN");
            OapiV2DepartmentListsubResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    List<OapiV2DepartmentListsubResponse.DeptBaseResponse> result = rsp.getResult();
                    resultArr = JSON.parseArray(JSON.toJSONString(result), DeptSimpleInfo.class);
                }
            } catch (ApiException e) {
                return resultArr;
            }
        }
        return resultArr;
    }

    /**
     * 根据父id查询子部门列表
     * @return 查询失败返回空
     */
    public String getDepartmentListsubid(Long parentDeptId) {
        String accessToken = getAccessToken();
        String resultStr = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_V2_DEPARTMENT_URL + DingdingUrlConstants.DEPARTMENT_LISTSUBID_URL);
            OapiV2DepartmentListsubidRequest req = new OapiV2DepartmentListsubidRequest();
            req.setDeptId(parentDeptId);
            OapiV2DepartmentListsubidResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiV2DepartmentListsubidResponse.DeptListSubIdResponse result = rsp.getResult();
                    resultStr = JSON.toJSONString(result);
                }
            } catch (ApiException e) {
                return resultStr;
            }
        }
        return resultStr;
    }

    /**
     * 根据部门id查询用户id列表
     * @param deptId
     * @return
     */
    public String getUserIdByDeptId(Long deptId) {
        String accessToken = getAccessToken();
        String resultStr = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_USER_URL + DingdingUrlConstants.USER_LISTID_URL);
            OapiUserListidRequest req = new OapiUserListidRequest();
            req.setDeptId(deptId);
            OapiUserListidResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiUserListidResponse.ListUserByDeptResponse result = rsp.getResult();
                    resultStr = JSON.toJSONString(result);
                }
            } catch (ApiException e) {
                return resultStr;
            }
        }
        return resultStr;
    }

    /**
     * 根据用户id查询详情
     * @param userId
     * @return
     */
    public UserInfo getUserDetailByUserid(String userId) {
        String accessToken = getAccessToken();
        UserInfo detail = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_V2_USER_URL + DingdingUrlConstants.USER_GET_DETAIL);
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            req.setUserid(userId);
            req.setLanguage("zh_CN");
            OapiV2UserGetResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiV2UserGetResponse.UserGetResponse result = rsp.getResult();
                    detail = JSON.parseObject(JSON.toJSONString(result), UserInfo.class);
                }
            } catch (ApiException e) {
                return detail;
            }
        }
        return detail;
    }

    /**
     * 根据部门id查询用户基础信息
     * @param deptId
     * @param cursor
     * @param size
     * @return
     */
    public JSONObject getUserSimpleByDeptid(Long deptId, Long cursor, Long size) {
        String accessToken = getAccessToken();
        JSONObject resultJson = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_USER_URL + DingdingUrlConstants.USER_GET_BASE);
            OapiUserListsimpleRequest req = new OapiUserListsimpleRequest();
            req.setDeptId(deptId);
            req.setCursor(cursor);
            req.setSize(size);
            req.setOrderField("modify_desc");
            req.setContainAccessLimit(false);
            req.setLanguage("zh_CN");
            OapiUserListsimpleResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiUserListsimpleResponse.PageResult result = rsp.getResult();
                    resultJson = new JSONObject();
                    resultJson.put("has_more", result.getHasMore());
                    resultJson.put("next_cursor", result.getNextCursor());
                    resultJson.put("list", JSON.parseArray(JSON.toJSONString(result.getList()), UserInfo.class));
                }
            } catch (ApiException e) {
                return resultJson;
            }
        }
        return resultJson;
    }

    /**
     * 根据部门id查询用户详情列表
     * @return
     */
    public JSONObject getUserListByDeptid(Long deptId, Long cursor, Long size) {
        String accessToken = getAccessToken();
        JSONObject resultJson = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_V2_USER_URL + DingdingUrlConstants.USER_GET_LIST);
            OapiV2UserListRequest req = new OapiV2UserListRequest();
            req.setDeptId(deptId);
            req.setCursor(cursor);
            req.setSize(size);
            req.setOrderField("modify_desc");
            req.setContainAccessLimit(false);
            req.setLanguage("zh_CN");
            OapiV2UserListResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiV2UserListResponse.PageResult result = rsp.getResult();
                    resultJson = new JSONObject();
                    resultJson.put("has_more", result.getHasMore());
                    resultJson.put("next_cursor", result.getNextCursor());
                    resultJson.put("list", JSON.parseArray(JSON.toJSONString(result.getList()), UserInfo.class));
                }
            } catch (ApiException e) {
                return resultJson;
            }
        }
        return resultJson;
    }


    /**
     * 发送工作通知
     * @param param
     * @return
     */
    public String sendWorkMsgByAsync(String targetType, Map<String, Object> param) {
        String accessToken = getAccessToken();
        String resultStr = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_WORK_MSG_URL + DingdingUrlConstants.WORK_MSG_SEND_URL);
            OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
            request.setAgentId(Long.valueOf(agentConfig.getAgentId()));
            if ("1".equals(targetType)) {
                request.setToAllUser(true);
            } else {
                // xxxx,xxxxx,xxxxx
                if ("2".equals(targetType)) {
                    request.setDeptIdList((String) param.get("deptIdListStr"));
                } else {
                    request.setUseridList((String) param.get("userIdListStr"));
                }
                request.setToAllUser(false);
            }
            // msgType默认 text,[text/image/file/link/markdown/oa/actionCard]
            JSONObject jmsg = JSON.parseObject(JSON.toJSONString(param.get("msg")));
            String msgType = jmsg.getString("msgtype");
            if (StringUtils.isEmpty(msgType)) {
                msgType = "text";
            }
            OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
            if (!"oa".equals(msgType) && !"actionCard".equals(msgType)) {
                msg.setMsgtype(msgType);
            }
            switch (msgType) {
                case "text":
                    msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
                    msg.getText().setContent(jmsg.getJSONObject("text").getString("content"));
                    break;
                case "image":
                    msg.setImage(new OapiMessageCorpconversationAsyncsendV2Request.Image());
                    msg.getImage().setMediaId(jmsg.getJSONObject("image").getString("mediaId"));
                    break;
                case "file":
                    msg.setFile(new OapiMessageCorpconversationAsyncsendV2Request.File());
                    msg.getFile().setMediaId(jmsg.getJSONObject("file").getString("mediaId"));
                    break;
                case "link":
                    msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link());
                    msg.getLink().setTitle(jmsg.getJSONObject("link").getString("title"));
                    msg.getLink().setText(jmsg.getJSONObject("link").getString("text"));
                    msg.getLink().setMessageUrl(jmsg.getJSONObject("link").getString("messageUrl"));
                    msg.getLink().setPicUrl(jmsg.getJSONObject("link").getString("picUrl"));
                    break;
                case "markdown":
                    msg.setMarkdown(new OapiMessageCorpconversationAsyncsendV2Request.Markdown());
                    msg.getMarkdown().setText(jmsg.getJSONObject("markdown").getString("text"));
                    msg.getMarkdown().setTitle(jmsg.getJSONObject("markdown").getString("title"));
                    break;
                case "oa": msg.setOa(new OapiMessageCorpconversationAsyncsendV2Request.OA());
                    msg.getOa().setHead(new OapiMessageCorpconversationAsyncsendV2Request.Head());
                    msg.getOa().getHead().setText("head");
                    msg.getOa().setBody(new OapiMessageCorpconversationAsyncsendV2Request.Body());
                    msg.getOa().getBody().setContent("xxx");
                    msg.setMsgtype("oa");
                    break;
                case "actionCard":
                    msg.setActionCard(new OapiMessageCorpconversationAsyncsendV2Request.ActionCard());
                    msg.getActionCard().setTitle("xxx123411111");
                    msg.getActionCard().setMarkdown("### 测试123111");
                    msg.getActionCard().setSingleTitle("测试测试");
                    msg.getActionCard().setSingleUrl("https://www.dingtalk.com");
                    msg.setMsgtype("action_card");
                    break;
                default:
                    break;
            }
            request.setMsg(msg);
            OapiMessageCorpconversationAsyncsendV2Response rsp = null;
            try {
                rsp = client.execute(request, accessToken);

                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    resultStr = String.valueOf(rsp.getTaskId());
                }
            } catch (ApiException e) {
                return resultStr;
            }
        }
        return resultStr;
    }

    /**
     * 根据任务id获取发送结果
     * @param taskId
     * @return
     */
    public String getMsgSendResult(Long taskId) {
        String accessToken = getAccessToken();
        String resultStr = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_WORK_MSG_URL + DingdingUrlConstants.WORK_MSG_GET_SEND_RESULT_URL);
            OapiMessageCorpconversationGetsendresultRequest req = new OapiMessageCorpconversationGetsendresultRequest();
            req.setAgentId(Long.valueOf(agentConfig.getAgentId()));
            req.setTaskId(taskId);
            OapiMessageCorpconversationGetsendresultResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiMessageCorpconversationGetsendresultResponse.AsyncSendResult result = rsp.getSendResult();
                    resultStr = JSON.toJSONString(result);
                }
            } catch (ApiException e) {
                return resultStr;
            }
        }
        return resultStr;
    }


    /**
     * 根据部门id查询部门详情
     * @return 查询失败返回空
     */
    public DeptDetailInfo getDeptDetailById(Long deptId) {
        String accessToken = getAccessToken();
        DeptDetailInfo deptDetailInfo = null;
        if (!StringUtils.isEmpty(accessToken)) {
            DingTalkClient client = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_V2_DEPARTMENT_URL + DingdingUrlConstants.DEPARTMENT_DETAIL_URL);
            OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest();
            req.setDeptId(deptId);
            req.setLanguage("zh_CN");
            OapiV2DepartmentGetResponse rsp = null;
            try {
                rsp = client.execute(req, accessToken);
                String errorCode = rsp.getErrorCode();
                if ("0".equals(errorCode)) {
                    OapiV2DepartmentGetResponse.DeptGetResponse result = rsp.getResult();
                    deptDetailInfo = JSON.parseObject(JSON.toJSONString(result), DeptDetailInfo.class);
                }
            } catch (ApiException e) {
                return deptDetailInfo;
            }
        }
        return deptDetailInfo;
    }

    /**
     * 通过扫描二维码返回的code值，得到用户相关信息
     */
    public String getUserIdByUnionId(String unionid) throws Exception {
        String accessToken = getAccessToken();
        DingTalkClient clientDingTalkClient = new DefaultDingTalkClient(DingdingUrlConstants.BASE_URL + DingdingUrlConstants.BASE_USER_URL + DingdingUrlConstants.GET_USERID_UNIONID_URL);
        OapiUserGetbyunionidRequest reqGetbyunionidRequest = new OapiUserGetbyunionidRequest();
        reqGetbyunionidRequest.setUnionid(unionid);
        OapiUserGetbyunionidResponse oapiUserGetbyunionidResponse = clientDingTalkClient.execute(reqGetbyunionidRequest, accessToken);

        // 根据userId获取用户信息
        String userid = oapiUserGetbyunionidResponse.getResult().getUserid();
        return userid;
    }


    public static com.aliyun.dingtalkoauth2_1_0.Client authClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

    /**
     * 获取用户token
     * @param authCode
     * @return
     * @throws Exception
     */
    //接口地址：注意/auth与钉钉登录与分享的回调域名地址一致
    public String getAuthAccessToken(String agentName, String authCode) throws Exception {
        com.aliyun.dingtalkoauth2_1_0.Client client = authClient();
        GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
                //应用基础信息-应用信息的AppKey,请务必替换为开发的应用AppKey
                .setClientId(agentConfig.getAppKey())
                //应用基础信息-应用信息的AppSecret，,请务必替换为开发的应用AppSecret
                .setClientSecret(agentConfig.getAppSecret())
                .setCode(authCode)
                .setGrantType("authorization_code");
        GetUserTokenResponse getUserTokenResponse = client.getUserToken(getUserTokenRequest);
        //获取用户个人token
        String accessToken = getUserTokenResponse.getBody().getAccessToken();
        return  getUserinfo(accessToken);

    }
    public static com.aliyun.dingtalkcontact_1_0.Client contactClient() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkcontact_1_0.Client(config);
    }
    /**
     * 获取用户个人信息
     * @param accessToken
     * @return
     * @throws Exception
     */
    public String getUserinfo(String accessToken) throws Exception {
        com.aliyun.dingtalkcontact_1_0.Client client = contactClient();
        GetUserHeaders getUserHeaders = new GetUserHeaders();
        getUserHeaders.xAcsDingtalkAccessToken = accessToken;
        //获取用户个人信息，如需获取当前授权人的信息，unionId参数必须传me
        String me = JSON.toJSONString(client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions()).getBody());
        System.out.println(me);
        return me;
    }

    /**
     * 钉钉部门简易信息类
     */
    @Data
    public static class DeptSimpleInfo {
        private Boolean autoAddUser;

        private Boolean createDeptGroup;

        private Long deptId;

        private String name;

        private Long parentId;
    }

    /**
     * 钉钉部门详情信息类
     */
    @Data
    public static class DeptDetailInfo {
        private Long deptId;

        private String name;

        private Long parentId;

        private String sourceIdentifier;

        private String tags;

        private Integer order;

        private String orgDeptOwner;

        private List<String> deptManagerUseridList;

    }

    @Data
    public static class UserInfo {
        private String userid;

        private String name;

        private String unionid;

        private String avatar;

        private String mobile;

        private String jobNumber;

        private String email;

        private List<Long> deptIdList;

    }

}
